package drds.server.buffer;

import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import sun.nio.ch.DirectBuffer;

/**
 * 
 * @author 曹正辉<330937205@qq.com>
 * 
 */
public class DirectByteBufferPool implements ByteBufferPool {
	private static final Logger LOGGER = LoggerFactory.getLogger("DirectByteBufferPool");
	public static final String THREAD_LOCAL_BYTEBUFFER_PREX = "$_";
	// private int prevAllocatedPage = 0;
	private final int pageSize;
	private final int pageNum;
	private final int blockSize;
	private Page[] pages;
	private AtomicInteger currentPageIndex;
	private final int readByteBufferBlock;

	/**
	 * 
	 * @param pageNum
	 *            页的个数
	 * @param pageSize
	 *            页的大小
	 * @param blockSize
	 * @param readByteBufferBlock
	 */
	public DirectByteBufferPool(//
			int pageNum,//
			int pageSize,//
			int blockSize,//
			int readByteBufferBlock) {//
		this.pageNum = pageNum;//
		this.pages = new Page[pageNum];//

		this.pageSize = pageSize;
		this.blockSize = blockSize;
		for (int i = 0; i < pageNum; i++) {
			pages[i] = new Page(ByteBuffer.allocateDirect(pageSize), blockSize);
		}
		// 当前页号
		this.currentPageIndex = new AtomicInteger(0);
		this.readByteBufferBlock = readByteBufferBlock;
	}

	public ByteBufferList byteBufferList() {
		return new ByteBufferList(this);
	}

	/**
	 * TODO 当页不够时，考虑扩展内存池的页的数量...........
	 */
	public ByteBuffer expandByteBuffer(ByteBuffer byteBuffer) {
		int oldCapacity = byteBuffer.capacity();
		int newCapacity = oldCapacity << 1;
		ByteBuffer newByteBuffer = allocate(newCapacity);
		if (newByteBuffer != null) {
			int newPosition = byteBuffer.position();
			/**
			 * limit set to position,and position set to 0. <br/>
			 * 写模式变成可读模式.
			 */
			byteBuffer.flip();
			newByteBuffer.put(byteBuffer);
			newByteBuffer.position(newPosition);
			recycle(byteBuffer);
			return newByteBuffer;
		}
		return null;
	}

	public ByteBuffer allocate(int size) {
		int blockNum = //
		size / blockSize + //
				(size % blockSize == 0 ? 0 : 1);
		int pageIndex = currentPageIndex.incrementAndGet() % pages.length;

		ByteBuffer byteBuffer = allocateByteBuffer(0, pageIndex, blockNum);
		/**
		 * 该区间请求失败
		 */
		if (byteBuffer == null) {
			byteBuffer = allocateByteBuffer(pageIndex, pages.length, blockNum);
		}
		return byteBuffer;
	}

	public void recycle(ByteBuffer byteBuffer) {
		if (!(byteBuffer instanceof DirectBuffer)) {
			byteBuffer.clear();
			return;
		}
		boolean recycled = false;

		DirectBuffer subByteBuffer = (DirectBuffer) byteBuffer;
		DirectBuffer parentByteBuffer = (DirectBuffer) subByteBuffer.attachment();
		//
		int blockNum = byteBuffer.capacity() / blockSize;
		int blockStartIndex = (int) ((subByteBuffer.address() - parentByteBuffer.address()) / this.blockSize);//
		int length = pages.length;
		for (int i = 0; i < length; i++) {//
			if ((recycled = pages[i].recycleSubByteBuffer(//
					(ByteBuffer) parentByteBuffer,//
					blockStartIndex,// 开始块index
					blockNum))) {//
				break;//
			}
		}
		if (recycled == false) {
			LOGGER.error("can not recycled buffer " + byteBuffer);
		}
	}

	private ByteBuffer allocateByteBuffer(//
			int startPageIndex,//
			int endPageIndex,//
			int blockNum) {//

		for (int i = startPageIndex; i < endPageIndex; i++) {
			ByteBuffer byteBuffer = pages[i].allocateSubByteBuffer(blockNum);
			if (byteBuffer != null) {
				currentPageIndex.getAndSet(i);
				return byteBuffer;
			}
		}
		return null;
	}

	public int getBlockSize() {
		return blockSize;
	}

	public int getPageSize() {
		return pageSize;
	}

	public int getPageNum() {
		return pageNum;
	}

	// TODO should fix it
	public long capacity() {
		return size();
	}

	public long size() {
		return (long) pageSize * blockSize * pageNum;
	}

	// TODO
	public int getAllCount() {
		return 0;
	}

	public int getReadByteBufferBlock() {
		return readByteBufferBlock;
	}

}
